/*
 * Copyright (c) 2018-2024 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "xdrbase.h"
#include "channel.h"
#include "api.h"

/**
 * @brief       API: set debug to JM or JS.
 *
 * @param[in]   debugreq     #1: debug request key values
 * @param[in]   host         #2: node name, NULL if set debug for JS.
 *
 * @retval      0            #1: succeed
 * @retval     -1            #2: failed
 *
 */
int
client_request_debug(struct request *debugreq, char *host)
{
    if (NULL == debugreq || 0 == debugreq->number) {
        log_message(ERR, NOCLASS, "%s: Must specify debug request.", __func__);
	return -1;
    }

    // check the first key to avoid unknown request from client.
    if (REQUEST_KEY_REQUEST_CODE != debugreq->keyvalues[0].key) {
        log_message(ERR, NOCLASS, "%s: First key must be request code for debug request.",
                    __func__);
	return -1;
    }

    int reqCode = atoi(debugreq->keyvalues[0].value);

    struct auth auth;
    gf_set_auth(&auth, commandParams[AUTH_KIND].string_value);

    unsigned int size; // for calculating the size of the request.
    size = gf_xdrsize_request(debugreq);
    size += gf_xdrsize_auth(&auth);
    size += HEADER_LEN;

    char *request;
    request = (char *)calloc(size, sizeof(char));
    if (NULL == request) {

        gf_xdr_free(gf_xdr_auth, (void *)&auth);
        log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc", size);
        quickpool_errno = ERROR_MEMORY;
	return -1;
    }

    XDR xdrs;
    xdrmem_create(&xdrs, request, MAXMESSAGELENGTH, XDR_ENCODE);

    struct header tohdr, outhdr;
    gf_init_header(&tohdr);
    if (JS_DEBUG == reqCode || JS_TIMING == reqCode) {

        tohdr.reqcode = BATCH_DEBUG;
    } else {

        tohdr.reqcode = CMD_JM_DEBUG;
    }

    if (!gf_xdr_message(&xdrs, debugreq, &tohdr, &auth, gf_xdr_request, NULL)) {

        // fail to encode request.
        log_message(ERR, NOCLASS, STR_FUNC_FAIL, __func__, "gf_xdr_message");
        xdr_destroy(&xdrs);
        FREEUP(request);
        gf_xdr_free(gf_xdr_auth, (void *)&auth);
        quickpool_errno = ERROR_XDR;

        return -1;
    }

    char *reply, *strCallNode;
    int cc, fd=-1;
    if (JS_DEBUG == reqCode || JS_TIMING == reqCode) {

        strCallNode = qp_getmastername(); // call JM to get the maste name.
        if (NULL == strCallNode) {
            // JM do not know who is master, let's try g_masterlist.
            strCallNode = g_masterlist;
        }

        cc = gf_callmaster(strCallNode, g_js_port, g_conntimeout, g_recvtimeout, g_connretries,
                           XDR_GETPOS(&xdrs), request, &outhdr, &reply, &fd); 
    } else {

        // JM debug, call the node from input parameter.
        strCallNode = host;
        cc = gf_callslave(strCallNode, g_jm_port, g_conntimeout, g_recvtimeout,
                          XDR_GETPOS(&xdrs), request, &outhdr, &reply, &fd);
    }

    if (0 < fd) {
        gf_chan_close(fd);
    }
    xdr_destroy(&xdrs);
    FREEUP(request);
    gf_xdr_free(gf_xdr_auth, (void *)&auth);

    if (0 > cc) { // communication in trouble.

        FREEUP(reply);
        log_message(ERR, NOCLASS, STR_FUNC_S_FAIL, __func__, "gf_callmaster", strCallNode);
        return -1;
    }

    quickpool_errno = outhdr.reqcode;
    if (quickpool_errno != 0) {

        // JM/JS replied error message, decode it and print out.
        xdrmem_create(&xdrs, reply, outhdr.length, XDR_DECODE);

        char *strErrMsg = NULL;
        if (!gf_xdr_string(&xdrs, &strErrMsg, &outhdr, NULL)) {

            xdr_destroy(&xdrs);
            FREEUP(reply);
            log_message(ERR, NOCLASS, STR_FUNC_FAIL, __func__, "gf_xdr_string");
            return -1;
        }

        if (NULL != strErrMsg) {
            log_message(ERR, NOCLASS, "%s", strErrMsg);
        } else {
            log_message(ERR, NOCLASS, "%s: unknown error occurs.", __func__);
        }

        FREEUP(strErrMsg);
        xdr_destroy(&xdrs);
        FREEUP(reply);

        return -1;
    }

    FREEUP(reply);

    return 0;
} // end function client_request_debug
